package myICGen;

import bit.minisys.minicc.icgen.Quat;
import bit.minisys.minicc.icgen.TemporaryValue;
import bit.minisys.minicc.parser.ast.*;
import bit.minisys.minicc.pp.internal.Q;
import mySemantic.ErrorPrint;

import javax.print.DocFlavor;
import java.util.*;

public class MyICBuilder implements ASTVisitor {
    Stack<Map<String, Symbol>> symbolTableStack = new Stack<>();
    Queue<Symbol> funcParams = new LinkedList<>();      //函数变量，在进入函数体时加入其中
    Stack<ASTNode> iterationBreakFlagStack = new Stack<>();   //储存循环体跳出flag的栈
    Stack<ASTNode> iterationContinueFlagStack = new Stack<>();  //储存循环体step flag的栈。

    private String type;
    private Symbol tmpSymbol = new Symbol();

    private Map<ASTNode, ASTNode> map;				// 使用map存储子节点的返回值，key对应子节点，value对应返回值，value目前类别包括ASTIdentifier,ASTIntegerConstant,TemportaryValue...
    private List<Quat> quats;						// 生成的四元式列表
    private Integer tmpId;							// 临时变量编号

    public MyICBuilder() {
        map = new HashMap<ASTNode, ASTNode>();
        quats = new LinkedList<Quat>();
        tmpId = 0;
    }
    public List<Quat> getQuats() {
        return quats;
    }

    @Override
    public void visit(ASTCompilationUnit program) throws Exception {
        symbolTableStack.push(new HashMap<String, Symbol>());
        for (ASTNode node : program.items) {
            if(node instanceof ASTFunctionDefine)
                visit((ASTFunctionDefine)node);
            else if(node instanceof ASTDeclaration)
                visit((ASTDeclaration) node);
        }
        symbolTableStack.pop();
    }

    @Override
    public void visit(ASTDeclaration declaration) throws Exception {
        // TODO Auto-generated method stub
        type = buildTypeByTokens(declaration.specifiers);
        for(ASTInitList initList : declaration.initLists)
        {
            visit(initList);
            tmpSymbol.type = type;
            if(!symbolTableStack.peek().containsKey(tmpSymbol.id))
                symbolTableStack.peek().put(tmpSymbol.id, new Symbol(tmpSymbol));
            else
                ErrorPrint.varDefinedAgain(tmpSymbol.id, "Identifier");
        }
    }

    @Override
    public void visit(ASTArrayDeclarator arrayDeclarator) throws Exception {
        Symbol saveSymbol = new Symbol(tmpSymbol);
        visit(arrayDeclarator.declarator);
        tmpSymbol.symbolType = Symbol.SymbolType.Array;
        visit(arrayDeclarator.expr);
        tmpSymbol = new Symbol(saveSymbol);
    }

    @Override
    public void visit(ASTVariableDeclarator variableDeclarator) throws Exception {
        visit(variableDeclarator.identifier);
        tmpSymbol.symbolType = Symbol.SymbolType.Variable;
    }

    @Override
    public void visit(ASTFunctionDeclarator functionDeclarator) throws Exception {
        // TODO Auto-generated method stub
        visit(functionDeclarator.declarator);
        tmpSymbol.symbolType = Symbol.SymbolType.Func;
        Symbol saveSymbol = new Symbol(tmpSymbol);
        for(ASTParamsDeclarator paramsDeclarator : functionDeclarator.params)
        {
            visit(paramsDeclarator);
            saveSymbol.params.add(type);
            tmpSymbol.type = type;
            funcParams.add(new Symbol(tmpSymbol));
        }
        tmpSymbol = new Symbol(saveSymbol);
    }

    @Override
    public void visit(ASTParamsDeclarator paramsDeclarator) throws Exception {
        // TODO Auto-generated method stub
        type = buildTypeByTokens(paramsDeclarator.specfiers);
        visit(paramsDeclarator.declarator);
    }

    @Override
    public void visit(ASTArrayAccess arrayAccess) throws Exception {
        // TODO Auto-generated method stub
        //visit(arrayAccess.arrayName);
        //String op = "[]";
        //ASTNode res = null;
        //ASTNode opnd1 = null;
        //ASTNode opnd2 = null;
        //TemporaryValue temporaryValue = new TemporaryValue(++tmpId);
    }

    @Override
    public void visit(ASTBinaryExpression binaryExpression) throws Exception {
        String op = binaryExpression.op.value;
        ASTNode res = null;
        ASTNode opnd1 = null;
        ASTNode opnd2 = null;

        String type1 = "";
        String type2 = "";

        if (op.equals("=")) {
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            res = map.get(binaryExpression.expr1);
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd1 = map.get(binaryExpression.expr2);
        }else if (op.equals("+=")){
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            res = map.get(binaryExpression.expr1);
            opnd1 = res;
            op = "+";
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }else if (op.equals("-=")){
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            res = map.get(binaryExpression.expr1);
            opnd1 = res;
            op = "-";
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }else if (op.equals("*=")){
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            res = map.get(binaryExpression.expr1);
            opnd1 = res;
            op = "*";
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }else if (op.equals("/=")){
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            res = map.get(binaryExpression.expr1);
            opnd1 = res;
            op = "/";
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }else if (op.equals("%=")){
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            res = map.get(binaryExpression.expr1);
            opnd1 = res;
            op = "+";
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }else if (op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/") || op.equals("%")) {
            // 四则运算，结果存储到临时变量。
            res = new TemporaryValue(++tmpId);
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            opnd1 = map.get(binaryExpression.expr1);
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        } else if (op.equals(">") || op.equals("<") || op.equals(">=") || op.equals("<=") || op.equals("==") || op.equals("!=")) {
            // 关系运算
            res = new TemporaryValue(++tmpId);
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            opnd1 = map.get(binaryExpression.expr1);
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        } else if (op.equals(">>") || op.equals("<<")) {
            // 移位运算
            res = new TemporaryValue(++tmpId);
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            opnd1 = map.get(binaryExpression.expr1);
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }else if (op.equals("||") || op.equals("&&")) {
            // 逻辑运算
            res = new TemporaryValue(++tmpId);
            visit(binaryExpression.expr1);
            type1 = tmpSymbol.type;
            opnd1 = map.get(binaryExpression.expr1);
            visit(binaryExpression.expr2);
            type2 = tmpSymbol.type;
            opnd2 = map.get(binaryExpression.expr2);
        }

        tmpSymbol.type = binaryExpressionIsMatched(type1, type2, op);
        if(tmpSymbol.type == null)
            return;

        // build quat
        Quat quat = new Quat(op, res, opnd1, opnd2);
        quats.add(quat);
        map.put(binaryExpression, res);
    }

    @Override
    public void visit(ASTBreakStatement breakStat) throws Exception {
        // TODO Auto-generated method stub
        Quat breakQuat = new Quat("JMP", null, iterationBreakFlagStack.peek(), null);
        quats.add(breakQuat);
        return;
    }

    @Override
    public void visit(ASTContinueStatement continueStatement) throws Exception {
        // TODO Auto-generated method stub
        Quat continueQuat = new Quat("JMP", null, iterationContinueFlagStack.peek(), null);
        quats.add(continueQuat);
        return;
    }

    @Override
    public void visit(ASTCastExpression castExpression) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void visit(ASTCharConstant charConst) throws Exception {
        map.put(charConst, charConst);
        tmpSymbol.type = "char";
    }

    @Override
    public void visit(ASTCompoundStatement compoundStat) throws Exception {
        symbolTableStack.push(new HashMap<>());
        for(Symbol param : funcParams)
        {
            symbolTableStack.peek().put(param.id, new Symbol(param));
        }
        funcParams.clear();
        for (ASTNode node : compoundStat.blockItems) {
            if(node instanceof ASTDeclaration) {
                visit((ASTDeclaration)node);
            }else if (node instanceof ASTStatement) {
                visit((ASTStatement)node);
            }
        }
        symbolTableStack.pop();
    }

    @Override
    public void visit(ASTConditionExpression conditionExpression) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void visit(ASTExpression expression) throws Exception {
        if(expression instanceof ASTArrayAccess) {
            visit((ASTArrayAccess)expression);
        }else if(expression instanceof ASTBinaryExpression) {
            visit((ASTBinaryExpression)expression);
        }else if(expression instanceof ASTCastExpression) {
            visit((ASTCastExpression)expression);
        }else if(expression instanceof ASTCharConstant) {
            visit((ASTCharConstant)expression);
        }else if(expression instanceof ASTConditionExpression) {
            visit((ASTConditionExpression)expression);
        }else if(expression instanceof ASTFloatConstant) {
            visit((ASTFloatConstant)expression);
        }else if(expression instanceof ASTFunctionCall) {
            visit((ASTFunctionCall)expression);
        }else if(expression instanceof ASTIdentifier) {
            visit((ASTIdentifier)expression);
            if (!isIdentifierExist(tmpSymbol.id))
                ErrorPrint.varNotDefined(tmpSymbol.id, tmpSymbol.symbolTypeToString());
            else
                tmpSymbol.type = findSymbolByID(tmpSymbol.id).type;
        }else if(expression instanceof ASTIntegerConstant) {
            visit((ASTIntegerConstant)expression);
        }else if(expression instanceof ASTMemberAccess) {
            visit((ASTMemberAccess)expression);
        }else if(expression instanceof ASTPostfixExpression) {
            visit((ASTPostfixExpression)expression);
        }else if(expression instanceof ASTStringConstant) {
            visit((ASTStringConstant)expression);
        }else if(expression instanceof ASTUnaryExpression) {
            visit((ASTUnaryExpression)expression);
        }else if(expression instanceof ASTUnaryTypename){
            visit((ASTUnaryTypename)expression);
        }
    }

    @Override
    public void visit(ASTExpressionStatement expressionStat) throws Exception {
        for (ASTExpression node : expressionStat.exprs) {
            visit((ASTExpression)node);
        }
    }

    @Override
    public void visit(ASTFloatConstant floatConst) throws Exception {
        map.put(floatConst, floatConst);
        tmpSymbol.type = "float";
    }

    @Override
    public void visit(ASTFunctionCall funcCall) throws Exception {
        // TODO Auto-generated method stub
        visit(funcCall.funcname);
        tmpSymbol.type = findSymbolByID(tmpSymbol.id).type;
        Symbol saveSymbol = new Symbol(tmpSymbol);

        if(findSymbolByID(tmpSymbol.id).type.equals(""))
        {
            ErrorPrint.varNotDefined(tmpSymbol.id, "Function");
        }

        List<String> funcParams = findSymbolByID(tmpSymbol.id).params;
        if(funcParams.size() != funcCall.argList.size())
        {
            ErrorPrint.paramsNotMatched(tmpSymbol.id, "Params' Num");
        }
        else {
            for (int i = 0; i < funcCall.argList.size(); i++) {
                ASTExpression arg = funcCall.argList.get(i);
                visit(arg);
                if (!tmpSymbol.type.equals(funcParams.get(i))) {
                    ErrorPrint.paramsNotMatched(saveSymbol.id, "Params' Type");
                }

                Quat pushArg = new Quat("push", null, map.get(arg), null);
                quats.add(pushArg);
            }
        }

        TemporaryValue temporaryValue = new TemporaryValue(++tmpId);
        Quat funCallQuat = new Quat("call", temporaryValue, map.get(funcCall.funcname), null);
        quats.add(funCallQuat);

        tmpSymbol = new Symbol(saveSymbol);
        map.put(funcCall, temporaryValue);
        return;
    }

    @Override
    public void visit(ASTGotoStatement gotoStat) throws Exception {
        // TODO Auto-generated method stub
        visit(gotoStat.label);
        Quat gotoQuat = new Quat("JMP", null, map.get(gotoStat.label), null);
        quats.add(gotoQuat);
        return;
    }

    @Override
    public void visit(ASTIdentifier identifier) throws Exception {
        tmpSymbol.id = identifier.value;
        map.put(identifier, identifier);
    }

    @Override
    public void visit(ASTInitList initList) throws Exception {
        visit(initList.declarator);
        if(tmpSymbol.symbolType.equals(Symbol.SymbolType.Func))
            tmpSymbol.symbolType = Symbol.SymbolType.FuncD;
        Symbol saveSymbol = new Symbol(tmpSymbol);
        for(ASTExpression expression : initList.exprs)
        {
            //声明赋值的四元式生成
            ASTBinaryExpression binaryExpression = new ASTBinaryExpression();
            binaryExpression.expr2 = expression;
            binaryExpression.op = new ASTToken();
            binaryExpression.op.value = "=";
            ASTIdentifier id = new ASTIdentifier();
            id.value = saveSymbol.id;
            if(!isIdentifierExist(id.value))
            {
                symbolTableStack.peek().put(id.value, saveSymbol);
            }
            binaryExpression.expr1 = id;
            visit(binaryExpression);
            symbolTableStack.peek().remove(id.value);
        }
        tmpSymbol = new Symbol(saveSymbol);
    }

    @Override
    public void visit(ASTIntegerConstant intConst) throws Exception {
        map.put(intConst, intConst);
        tmpSymbol.type = "int";
    }

    @Override
    public void visit(ASTIterationDeclaredStatement iterationDeclaredStat) throws Exception {
        // TODO Auto-generated method stub
        ASTNode opnd1 = null;
        symbolTableStack.push(new HashMap<>());
        visit(iterationDeclaredStat.init);

        TemporaryValue condJudgeFlag = new TemporaryValue(++tmpId);
        TemporaryValue condFalseFlag = new TemporaryValue(++tmpId); //跳出循环
        TemporaryValue iterationBodyFlag = new TemporaryValue(++tmpId); //循环体开始
        TemporaryValue stepFlag = new TemporaryValue(++tmpId);

        iterationBreakFlagStack.push(condFalseFlag);
        iterationContinueFlagStack.push(stepFlag);

        Quat condJudgeFlagQuat = new Quat("FLAG", null, condJudgeFlag, null);   //条件判断起始标签。
        quats.add(condJudgeFlagQuat);

        for(ASTExpression condexp : iterationDeclaredStat.cond) //条件判断部分
            visit(condexp);
        opnd1 = map.get(iterationDeclaredStat.cond.getLast());

        Quat condQuat = new Quat("JF", null,condFalseFlag, opnd1);
        quats.add(condQuat);


        Quat iterationBodyFlagQuat = new Quat("FLAG", null, iterationBodyFlag, null);
        quats.add(iterationBodyFlagQuat);

        visit(iterationDeclaredStat.stat);  //循环体
        Quat jmpStepQuat = new Quat("JMP", null, stepFlag, null);   //跳转到步增部分
        quats.add(jmpStepQuat);


        Quat jmpStepFlagQuat = new Quat("FLAG", null, stepFlag, null);
        quats.add(jmpStepFlagQuat);
        for(ASTExpression stepExp : iterationDeclaredStat.step)
            visit(stepExp);

        Quat jmpCondQuat = new Quat("JMP", null, condJudgeFlag, null);
        quats.add(jmpCondQuat);

        Quat jfCondFalseFlag = new Quat("FLAG", null, condFalseFlag, null);
        quats.add(jfCondFalseFlag);

        iterationBreakFlagStack.pop();
        iterationContinueFlagStack.pop();
        symbolTableStack.pop();
    }

    @Override
    public void visit(ASTIterationStatement iterationStat) throws Exception {
        // TODO Auto-generated method stub
        ASTNode opnd1 = null;
        symbolTableStack.push(new HashMap<>());
        for(ASTExpression initExp : iterationStat.init)
            visit(initExp);

        TemporaryValue condJudgeFlag = new TemporaryValue(++tmpId);
        TemporaryValue condFalseFlag = new TemporaryValue(++tmpId); //跳出循环
        TemporaryValue iterationBodyFlag = new TemporaryValue(++tmpId); //循环体开始
        TemporaryValue stepFlag = new TemporaryValue(++tmpId);
        iterationBreakFlagStack.push(condFalseFlag);
        iterationContinueFlagStack.push(stepFlag);


        Quat condJudgeFlagQuat = new Quat("FLAG", null, condJudgeFlag, null);   //条件判断起始标签。
        quats.add(condJudgeFlagQuat);

        for(ASTExpression condexp : iterationStat.cond) //条件判断部分
            visit(condexp);
        opnd1 = map.get(iterationStat.cond.getLast());


        Quat condQuat = new Quat("JF", null , condFalseFlag, opnd1);
        quats.add(condQuat);


        Quat iterationBodyFlagQuat = new Quat("FLAG", null, iterationBodyFlag, null);
        quats.add(iterationBodyFlagQuat);

        visit(iterationStat.stat);  //循环体

        Quat jmpStepQuat = new Quat("JMP", null, stepFlag, null);   //跳转到步增部分
        quats.add(jmpStepQuat);


        Quat jmpStepFlagQuat = new Quat("FLAG", null, stepFlag, null);
        quats.add(jmpStepFlagQuat);
        for(ASTExpression stepExp : iterationStat.step)
            visit(stepExp);

        Quat jmpCondQuat = new Quat("JMP", null, condJudgeFlag, null);
        quats.add(jmpCondQuat);

        Quat jfCondFalseFlag = new Quat("FLAG", null, condFalseFlag, null);
        quats.add(jfCondFalseFlag);

        iterationBreakFlagStack.pop();
        iterationContinueFlagStack.pop();
        symbolTableStack.pop();
    }

    @Override
    public void visit(ASTLabeledStatement labeledStat) throws Exception {
        // TODO Auto-generated method stub
        visit(labeledStat.label);
        Quat flagQuat = new Quat("FLAG", null, map.get(labeledStat.label), null);
        quats.add(flagQuat);
        visit(labeledStat.stat);
    }

    @Override
    public void visit(ASTMemberAccess memberAccess) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void visit(ASTPostfixExpression postfixExpression) throws Exception {
        //后缀表达式使用opnd2储存
        String op = postfixExpression.op.value;
        visit(postfixExpression.expr);
        TemporaryValue res = new TemporaryValue(++tmpId);
        Quat postfixQuat = new Quat(op, res, null, map.get(postfixExpression.expr));
        quats.add(postfixQuat);
        map.put(postfixExpression, res);
        return;
    }

    @Override
    public void visit(ASTReturnStatement returnStat) throws Exception {
        // TODO Auto-generated method stub
        String op = "ret";
        ASTNode opnd1 = null;
        if(returnStat.expr != null) {
            for (ASTExpression retExp : returnStat.expr)
                visit(retExp);

            opnd1 = map.get(returnStat.expr.getLast());
        }
        Quat retQuat = new Quat(op, null, opnd1, null);
        quats.add(retQuat);
        return;
    }

    @Override
    public void visit(ASTSelectionStatement selectionStat) throws Exception {
        ASTNode opnd1 = null;
        for(ASTExpression condexp : selectionStat.cond)
            visit(condexp);
        opnd1 = map.get(selectionStat.cond.getLast());
        TemporaryValue jfFlag = new TemporaryValue(++tmpId);
        Quat jfQuat = new Quat("JF", null, jfFlag, opnd1);
        quats.add(jfQuat);

        TemporaryValue jmpFlag = new TemporaryValue(++tmpId);   //跳出条件部分的flag
        if(selectionStat.then != null) {
            visit(selectionStat.then);
            Quat jmpQuat = new Quat("JMP", null, jmpFlag, null);
            quats.add(jmpQuat);
        }

        Quat jfFlagQuat = new Quat("FLAG", null, jfFlag, null);
        quats.add(jfFlagQuat);

        if(selectionStat.otherwise != null) {
            visit(selectionStat.otherwise);
        }
        Quat jmpFlagQuat = new Quat("FLAG", null, jmpFlag, null);
        quats.add(jmpFlagQuat);
    }

    @Override
    public void visit(ASTStringConstant stringConst) throws Exception {
        map.put(stringConst, stringConst);
        tmpSymbol.type = "StringConst";
    }

    @Override
    public void visit(ASTTypename typename) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void visit(ASTUnaryExpression unaryExpression) throws Exception {
        // TODO Auto-generated method stub
        String op = unaryExpression.op.value;
        visit(unaryExpression.expr);
        TemporaryValue res = new TemporaryValue(++tmpId);
        Quat unaryQuat = new Quat(op, res, map.get(unaryExpression.expr), null);
        quats.add(unaryQuat);

        map.put(unaryExpression, res);
    }

    @Override
    public void visit(ASTUnaryTypename unaryTypename) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void visit(ASTFunctionDefine functionDefine) throws Exception {
        funcParams.clear();
        type = buildTypeByTokens(functionDefine.specifiers);
        tmpSymbol.type = type;
        visit(functionDefine.declarator);
        if(!symbolTableStack.peek().containsKey(tmpSymbol.id) || (symbolTableStack.peek().get(tmpSymbol.id).symbolType.equals(Symbol.SymbolType.FuncD)))
            symbolTableStack.peek().put(tmpSymbol.id, new Symbol(tmpSymbol));
        else
            ErrorPrint.varDefinedAgain(tmpSymbol.id, "Function");
        ASTIdentifier funcID = new ASTIdentifier();
        funcID.value = tmpSymbol.id;
        Quat funcBody = new Quat("proc", null, funcID, null);
        quats.add(funcBody);
        visit(functionDefine.body);
        Quat funcEnd = new Quat("endp", null, funcID, null);
        quats.add(funcEnd);
    }

    @Override
    public void visit(ASTDeclarator declarator) throws Exception {
        // TODO Auto-generated method stub
        if(declarator instanceof ASTFunctionDeclarator)
        {
            visit((ASTFunctionDeclarator) declarator);
        }
        else if(declarator instanceof ASTArrayDeclarator)
        {
            visit((ASTArrayDeclarator) declarator);
        }
        else if(declarator instanceof ASTVariableDeclarator)
        {
            visit((ASTVariableDeclarator)declarator);
        }
    }

    @Override
    public void visit(ASTStatement statement) throws Exception {
        if(statement instanceof ASTIterationDeclaredStatement) {
            visit((ASTIterationDeclaredStatement)statement);
        }else if(statement instanceof ASTIterationStatement) {
            visit((ASTIterationStatement)statement);
        }else if(statement instanceof ASTCompoundStatement) {
            visit((ASTCompoundStatement)statement);
        }else if(statement instanceof ASTSelectionStatement) {
            visit((ASTSelectionStatement)statement);
        }else if(statement instanceof ASTExpressionStatement) {
            visit((ASTExpressionStatement)statement);
        }else if(statement instanceof ASTBreakStatement) {
            visit((ASTBreakStatement)statement);
        }else if(statement instanceof ASTContinueStatement) {
            visit((ASTContinueStatement)statement);
        }else if(statement instanceof ASTReturnStatement) {
            visit((ASTReturnStatement)statement);
        }else if(statement instanceof ASTGotoStatement) {
            visit((ASTGotoStatement)statement);
        }else if(statement instanceof ASTLabeledStatement) {
            visit((ASTLabeledStatement)statement);
        }
    }

    @Override
    public void visit(ASTToken token) throws Exception {
        // TODO Auto-generated method stub

    }


    private String buildTypeByTokens(List<ASTToken> tokens)
    {
        StringBuilder stringBuilder = new StringBuilder();
        for(ASTToken token : tokens)
        {
            stringBuilder.append(token.value);
        }
        return stringBuilder.toString();
    }


    private boolean isIdentifierExist(String id) throws Exception {
        if(findSymbolByID(id).type != "")
            return true;
        else {
            symbolTableStack.peek().put(id, null);
            return false;
        }
    }

    //需要进行兼容性检查
    private String binaryExpressionIsMatched(String type1, String type2, String op) throws Exception {
        String retType = null;
        switch (op)
        {
            case "=":
            case "+=":
            case "-=":
            case "/=":
            case "*=":
                if (!numTypeOK(type1, type2)) {
                    ErrorPrint.operateNumNotMatched(op);
                }
                retType = type1;
                break;
            case "+":
            case "-":
            case "*":
            case "/":
                if (!numTypeOK(type1, type2) && !numTypeOK(type2, type1)) {
                    ErrorPrint.operateNumNotMatched(op);
                }
                retType = higherExpresstionType(type1, type2);
                break;
            case ">":
            case "<":
            case ">=":
            case "<=":
                if (!numTypeOK(type1, type2)) {
                    ErrorPrint.operateNumNotMatched(op);
                }
                retType = "int";
                break;
            case "%":
            case "%=":
            case "<<":
            case ">>":
            case "<<=":
            case ">>=":
                if (!type1.equals("int") || !type2.equals("int")) {
                    ErrorPrint.operateNumNotMatched(op);
                }
                retType = "int";
                break;
            case "||":
            case "&&":
                retType = "int";
                break;
            default:
                System.out.println("Operator not defined");
                retType = null;
                break;
        }
        return retType;
    }

    private boolean numTypeOK(String type1 , String type2)
    {
        int level1 = 0;
        int level2 = 0;
        if(type1.equals("char"))
            level1 = 0;
        else if(type1.equals("int"))
            level1 = 1;
        else if(type1.equals("float"))
            level1 = 2;
        else if(type1.equals("double"))
            level1 = 3;
        else if(type1.equals("StringConst"))
            level1 = -1;

        if(type2.equals("char"))
            level2 = 0;
        else if(type2.equals("int"))
            level2 = 1;
        else if(type2.equals("float"))
            level2 = 2;
        else if(type2.equals("double"))
            level2 = 3;
        else if(type2.equals("StringConst"))
            level2 = -1;
        if(level1 >= 0 && level2 >= 0)
            return level1 >= level2;
        else
            return level1 == level2;

    }

    private String higherExpresstionType(String type1, String type2)
    {
        String retType = "";
        if(type1.equals("double") || type2.equals("double"))
            retType = "double";
        else if(type1.equals("float") || type2.equals("float"))
            retType = "float";
        else if(type1.equals("int") || type2.equals("int"))
            retType = "int";
        else if(type1.equals("char") || type2.equals("char"))
            retType = "char";
        return retType;
    }

    private Symbol findSymbolByID(String id)
    {
        for(int i = symbolTableStack.size() - 1; i >= 0; i--)
        {
            if(symbolTableStack.get(i).containsKey(id)) {
                if(symbolTableStack.get(i).get(id) == null)
                    return new Symbol();
                else
                    return symbolTableStack.get(i).get(id);
            }
        }
        return new Symbol();
    }

}
